package com.zbl.zblproject.pay.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayOpenAuthTokenAppRequest;
import com.alipay.api.response.AlipayOpenAuthTokenAppResponse;
import com.alipay.demo.trade.model.builder.AlipayTradeRefundRequestBuilder;
import com.alipay.demo.trade.model.result.AlipayF2FRefundResult;
import com.alipay.demo.trade.service.AlipayTradeService;
import com.github.wxpay.sdk.WXPay;
import com.google.common.base.Preconditions;
import com.zbl.jdbc.ConManager2;
import com.zbl.jdbc.JdbcTest;
import com.zbl.zblproject.core.entity.AdminUser;
import com.zbl.zblproject.core.entity.Result;
import com.zbl.zblproject.core.mapper.AdminUserMapper;
import com.zbl.zblproject.core.utils.ResultUtil;
import com.zbl.zblproject.core.utils.StringUtil;
import com.zbl.zblproject.core.utils.TimeUtil;
import com.zbl.zblproject.pay.entity.AlipayProperties;
import com.zbl.zblproject.pay.entity.PayOrder;
import com.zbl.zblproject.pay.entity.PayOrderItem;
import com.zbl.zblproject.pay.entity.StatisticsTable;
import com.zbl.zblproject.pay.mapper.AlipayTokenMapper;
import com.zbl.zblproject.pay.mapper.PayOrderItemMapper;
import com.zbl.zblproject.pay.service.PayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author youlanqiang
 * @version 1.0
 * @date 2018/11/5
 */
@Api(tags = "支付接口")
@Controller
@RequestMapping("/pay")
public class PayController {

    private static final Logger logger = LoggerFactory.getLogger(PayController.class);

    @Autowired
    private PayOrderItemMapper payOrderItemMapper;

    @Autowired
    private PayService payService;

    @Autowired
    private AdminUserMapper userMapper;

    @Autowired
    private AlipayTradeService alipayTradeService;

    @Autowired
    private AlipayProperties aliPayProperties;

    @Autowired
    private WXPay wxPay;

    @Autowired
    private AlipayTokenMapper alipayTokenMapper;


    private List<PayOrder> parseOrders(int userId, String json) {
        logger.info("json数值结构:{}", json);
        List<PayOrder> orders = new ArrayList<>();
        JSONArray array = JSONArray.parseArray(json);
        JSONObject object;
        List<PayOrderItem> items;
        for (int i = 0; i < array.size(); i++) {
            object = array.getJSONObject(i);
            PayOrder order = new PayOrder();
            order.setStatus(0);
            order.setDiscount(object.getBigDecimal("myDiscount"));
            order.setMode(object.getInteger("mode"));
            if (order.getMode() == 1 || order.getMode() == 2) {
                //支付宝或微信支付
                Preconditions.checkArgument(object.containsKey("payCode"), "线上订单必须传入线上订单号.");
                String payCode = object.getString("payCode");
                order.setPayCode(payCode);
            }

            /**git
             * 应收账款 receivable
             */
            order.setReceivable(object.getBigDecimal("singleMoney"));
            /**
             * 实收 officialReceipts
             */
            order.setOfficialReceipts(object.getBigDecimal("realmoney"));
            /**
             * 找零 changeNote
             */
            order.setChangeNote(object.getBigDecimal("payChange"));
            /**
             * 额外金额
             * 在银联支付中 additionalPayment 表示额外支付的金钱
             */
            if (object.containsKey("additionalPayment")) {
                order.setAdditionalPayment(object.getBigDecimal("additionalPayment"));
            }

            order.setUserId(userId);

            String time = object.getString("createTime");
            if (!StringUtil.isNullOrEmpty(time)) {
                order.setCreateTime(LocalDateTime.parse(time));
            } else {
                order.setCreateTime(LocalDateTime.now());
            }

            /**
             * 将物品单转化为 PayOrderItem
             */
            items = new ArrayList<>();
            JSONArray arrayOfTheItem = object.getJSONArray("goodsList");
            for (int f = 0; f < arrayOfTheItem.size(); f++) {
                JSONObject item = arrayOfTheItem.getJSONObject(f);
                PayOrderItem orderItem = new PayOrderItem();
                orderItem.setDiscount(item.getBigDecimal("discount"));
                orderItem.setGoodsId(item.getInteger("goodsId"));
                System.out.println(item.getString("goodNum"));
                orderItem.setGoodsNum(item.getFloat("goodNum"));
                orderItem.setSinglePrice(item.getBigDecimal("marketPrice"));
                orderItem.setGoodsName(item.getString("goodsName"));
                items.add(orderItem);
            }
            order.setItems(items);
            orders.add(order);
        }
        return orders;
    }


    @PostMapping("/get-local-order")
    @ResponseBody
    @ApiOperation("获取订单并备份到本地")
    public Result getDifferentOrder(@RequestParam("json") String json) {
        List<PayOrder> orders = JSONObject.parseArray(json, PayOrder.class);
        try {
            payService.synOrder(orders);
            return ResultUtil.success("成功!");
        } catch (RuntimeException e) {
            return ResultUtil.error(e.getMessage());
        }
    }


    @GetMapping("/sales-page/{id}/{catId}/{supId}")
    @ResponseBody
    @ApiOperation("查看销售报表")
    public Result salesPage(@ApiParam("开始时间") @RequestParam("start") String start,
                            @ApiParam("结束时间") @RequestParam("end") String end,
                            @ApiParam("用户ID") @PathVariable int id,
                            @ApiParam("商品名称") @RequestParam("goodsName") String goodsName,
                            @ApiParam("分类id") @PathVariable int catId,
                            @ApiParam("供应商id") @PathVariable int supId) {
        try {
            LocalDateTime startTime = TimeUtil.parseTime(start);
            LocalDateTime endTime = TimeUtil.parseTime(end);
            if (goodsName.equals("undefined") || "".equals(goodsName) || goodsName.equals(null)||" ".equals(goodsName)) {
                goodsName = "";
            } else {
                goodsName = "'%" + goodsName + "%'";
            }
            JSONObject result = payService.salesPage(startTime, endTime, id, goodsName, catId, supId);
            return ResultUtil.success("成功", result);
        } catch (RuntimeException e) {
            return ResultUtil.error(e.getMessage());
        }
    }

    @GetMapping("/order-list/{current}/{size}/{start}/{end}/{mode}")
    @ResponseBody
    @ApiOperation("查看收银明细")
    public Result orderList(@ApiParam("用户ID，为-1表示全部") @RequestParam("userId") int userId,
                            @ApiParam("开始事件") @PathVariable String start,
                            @ApiParam("结束事件") @PathVariable String end,
                            @ApiParam("当前页") @PathVariable int current,
                            @ApiParam("数量") @PathVariable int size,
                            @ApiParam("付款方式") @PathVariable int mode) {
        //分页
        try {
            LocalDateTime startTime = TimeUtil.parseTime(start);
            LocalDateTime endTime = TimeUtil.parseTime(end);
            JSONObject page = payService.pageForOrderList(startTime, endTime, userId, current, size, mode);
            return ResultUtil.success("成功!", page);
        } catch (RuntimeException e) {
            return ResultUtil.error(e.getMessage());
        }
    }


    @GetMapping("/today-order/{userId}")
    @ResponseBody
    @ApiOperation("获取今天的小票订单")
    public Result todayOrder(@ApiParam("查询订单") @RequestParam("orderSn") String sn,
                             @ApiParam("用户ID") @PathVariable int userId) {
        return ResultUtil.success("成功", payService.todaySuccessPayOrders(sn, userId));
    }


    @GetMapping("/get-payorder/{orderNo}")
    @ResponseBody
    @ApiOperation("获取小票信息")
    public Result getPayOrder(@ApiParam("订单号") @PathVariable String orderNo) {
        try {
            JSONObject object = payService.payOrderInfo(orderNo);
            return ResultUtil.success("成功", object);
        } catch (RuntimeException e) {
            logger.info(e.getMessage());
            return ResultUtil.error(e.getMessage());
        }
    }


    @GetMapping("/online-order/{orderSn}")
    @ResponseBody
    @ApiOperation("查询线上订单号")
    public Result onlineOrderSn(@ApiParam("订单号") @PathVariable String orderSn) {
        String onlineOrder = payService.getPayOrderOnlineOrder(orderSn);
        if (onlineOrder == null) {
            return ResultUtil.error("失败!");
        }
        return ResultUtil.success("成功!", onlineOrder);
    }


//    @PostMapping("/base/{sn}")
//    @ResponseBody
//    @ApiOperation("订单支付")
//    public Result basePay(@ApiParam("用户ID") @RequestParam("userId") int userId,
//                          @ApiParam("收营员编码") @PathVariable String sn,
//                          @ApiParam("订单信息") @RequestParam("items") String items) {
//        try {
//            List<PayOrder> orders = parseOrders(userId, items);
//            logger.info("收银订单创建 userId:{}", userId);
//            AdminUser user = getUserById(userId);
//            List<String> list = payService.createBaseOrders(sn, user, orders);
//            return ResultUtil.success("成功", list);
//        } catch (RuntimeException e) {
//            e.printStackTrace();
//            return ResultUtil.error(e.getMessage());
//        }
//    }


    @PostMapping("/base/{sn}")
    @ResponseBody
    @ApiOperation("订单支付")
    public Result basePay(@ApiParam("用户ID") @RequestParam("userId") int userId,
                          @ApiParam("收营员编码") @PathVariable String sn,
                          @ApiParam("订单信息") @RequestParam("items") String items,
                          @ApiParam("会员卡号") @RequestParam("clubcard") String clubcard,
                          @ApiParam("订单编号") @RequestParam("ordersn") String ordersn
    ) {
        try {

            logger.info("订单支付开始");
            logger.info("会员卡号：clubcard=" + clubcard);
            logger.info("订单编号：clubcard=" + ordersn);

            //1.ordersn     如果空  继续创建 原来逻辑 不变
            //2.ordersn     officialReceipts 实收金额 x1   1块钱1 积分

            if ("".equals(ordersn) || "null".equals(ordersn)) {
                List<PayOrder> orders = parseOrders(userId, items);
                logger.info("收银订单创建 userId:{}", userId);
                AdminUser user = getUserById(userId);//查询收银人员信息
                //创建支付订单
                List<String> list = payService.createBaseOrders(sn, user, orders);
                logger.info("订单编号：clubcard=" + list.toString());


                //加积分
                if (null != clubcard && !"".equals(clubcard)) {
                    for (PayOrder p : orders) {
                        BigDecimal b = p.getOfficialReceipts();//实收金额
                        JdbcTest.upJF(b.intValue(), clubcard);
                        logger.info("JdbcTest success " + clubcard + "||" + b.intValue());
                    }
                }
                //厦门店泰格系统加积分
                if (null != clubcard && !"".equals(clubcard)) {
                    System.out.println("厦门店泰格系统加积分开始------");
                    for (PayOrder p : orders) {
                        //15888341126
                        //加积分

                        int rs=0;//实收金额- 找零
                        BigDecimal b = p.getOfficialReceipts();
                        BigDecimal a=p.getChangeNote();//
                        if(a.intValue()>0){
                            rs=b.intValue()-a.intValue();
                        }

                        //获取原来的积分
                        String yljf=ConManager2.selectByteYLJF(clubcard);

                        //累加
                        Float yljf2=Float.valueOf(yljf);
                        int f3=yljf2.intValue()+rs;

                        //根据手机号加积分
                        ConManager2.update1(f3, clubcard);
                        //根据编号来更新
                        ConManager2.update2(f3, clubcard);


                        logger.info("加积分ConManager2 success----------");


                        System.out.println("厦门店泰格系统加费金额开始------");

                        //获取消费金额
                        String s=ConManager2.selectByteXFJE(clubcard);

                        //累加
                        Float f=Float.valueOf(s);

                        int f2=f.intValue()+rs;

                        //按手机号更新
                        ConManager2.update3(f2,clubcard);
                        //按编号更新
                        ConManager2.update3(f2,clubcard);

                        logger.info("加累加消费金额ConManager2 success ");



                    }
                }

                return ResultUtil.success("成功", list);

            } else {
                //继续生成一调 和原来订单号一样的 订单记录
                List<PayOrder> orders = parseOrders(userId, items);
                logger.info("收银订单创建 userId:{}", userId);
                AdminUser user = getUserById(userId);//查询收银人员信息
                //创建支付订单 订单号相同
                List<String> list = payService.createBaseOrdersRepetition(ordersn, user, orders);
                logger.info("订单编号：clubcard创建成功！");
                logger.info("订单编号：clubcard=" + list.toString());

                //加积分
                if (null != clubcard && !"".equals(clubcard)) {
                    for (PayOrder p : orders) {
                        BigDecimal b = p.getOfficialReceipts();//实收金额
                        JdbcTest.upJF(b.intValue(), clubcard);
                        logger.info("JdbcTest success " + clubcard + "||" + b.intValue());
                    }
                }

                //厦门店泰格系统加积分
                if (null != clubcard && !"".equals(clubcard)) {
                    System.out.println("厦门店泰格系统加积分开始------");
                    for (PayOrder p : orders) {
                        //15888341126
                        //加积分

                        int rs=0;//实收金额- 找零
                        BigDecimal b = p.getOfficialReceipts();
                        BigDecimal a=p.getChangeNote();//
                        if(a.intValue()>0){
                            rs=b.intValue()-a.intValue();
                        }

                        //获取原来的积分
                        String yljf=ConManager2.selectByteYLJF(clubcard);

                        //累加
                        Float yljf2=Float.valueOf(yljf);
                        int f3=yljf2.intValue()+rs;

                        //根据手机号加积分
                        ConManager2.update1(f3, clubcard);
                        //根据编号来更新
                        ConManager2.update2(f3, clubcard);


                        logger.info("加积分ConManager2 success----------");


                        System.out.println("厦门店泰格系统加费金额开始------");

                        //获取消费金额
                        String s=ConManager2.selectByteXFJE(clubcard);

                        //累加
                        Float f=Float.valueOf(s);

                        int f2=f.intValue()+rs;

                        //按手机号更新
                        ConManager2.update3(f2,clubcard);
                        //按编号更新
                        ConManager2.update3(f2,clubcard);

                        logger.info("加累加消费金额ConManager2 success ");



                    }
                }

                return ResultUtil.success("成功", list);

            }


        } catch (RuntimeException e) {
            e.printStackTrace();
            return ResultUtil.error(e.getMessage());
        }
    }


    @RequestMapping("/alipay-return")
    @ApiOperation("支付宝回调接口")
    public String alipayRefund(HttpServletRequest request) {
        try {
            Map<String, String> params = new HashMap<>();
            Map requestParams = request.getParameterMap();
            for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
                String name = (String) iter.next();
                String[] values = (String[]) requestParams.get(name);
                String valueStr = "";
                for (int i = 0; i < values.length; i++) {
                    valueStr = (i == values.length - 1) ? valueStr + values[i]
                            : valueStr + values[i] + ",";
                }
                //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
                params.put(name, valueStr);
            }
            //获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
            //支付宝用户号

            //第三方授权code
            String app_auth_code = new String(request.getParameter("app_auth_code").getBytes("ISO-8859-1"), "UTF-8");//获的第三方登录用户授权app_auth_code


            //使用auth_code换取接口access_token及用户userId
            //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","应用APPID",privateKey,"json","UTF-8",publicKey,"RSA2");//正常环境下的网关
            //AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipaydev.com/gateway.do", "沙箱环境下的应用APPID", privateKey, "json", "UTF-8", publicKey, "RSA2");//沙箱下的网关

            AlipayClient alipayClient = new DefaultAlipayClient(aliPayProperties.getGatewayUrl(), aliPayProperties.getAppid(),
                    aliPayProperties.getAppPrivateKey(), "json", "UTF-8", aliPayProperties.getAlipayPublicKey(), "RSA2");//沙箱下的网关

            AlipayOpenAuthTokenAppRequest requestLogin1 = new AlipayOpenAuthTokenAppRequest();
            requestLogin1.setBizContent("{" +
                    "\"grant_type\":\"authorization_code\"," +
                    "\"code\":\"" + app_auth_code + "\"" +
                    "}");

            //第三方授权
            AlipayOpenAuthTokenAppResponse responseToken = alipayClient.execute(requestLogin1);
            if (responseToken.isSuccess()) {
                //保存
                String value = responseToken.getAppAuthToken();
                if (alipayTokenMapper.size() == 0) {
                    alipayTokenMapper.insertAuthToken(value);
                } else {
                    alipayTokenMapper.updateAuthToken(value);
                }
                return "successPage";
            } else {
                return "errorPage";
            }
        } catch (Exception e) {
            return "errorPage";
        }
    }

    @PostMapping("/some-refund")
    @ResponseBody
    @ApiOperation("退部分款")
    public Result refundByItem(@ApiParam("线上订单号") @RequestParam("orderNo") String orderNo,
                               @ApiParam("退款的商品") @RequestParam("itemIds") Long[] ids) {
//        if(true){
//            return ResultUtil.error("该接口暂未开放.");
//        }
        //todo 部分退款
        PayOrder order = payService.getOrderByOnlineSn(orderNo);

        if (order == null) {
            return ResultUtil.error("没有发现这个订单！");
        }

        if (order.getStatus() != 1) {
            return ResultUtil.error("订单号未付款成功!");
        }

        List<PayOrderItem> items = payOrderItemMapper.selectBatchIds(Arrays.asList(ids));

        if (items.isEmpty()) {
            return ResultUtil.error("没有需要退款的商品");
        }

        if (order.getMode() == 0) {
            return ResultUtil.error("普通退款单未开放!");
        } else if (order.getMode() == 1) {
            //支付宝退款
            BigDecimal total = payService.returnAlipayItems(order, items);
        } else if (order.getMode() == 2) {
            //微信退款
            return ResultUtil.error("微信退款暂未开放!");
        } else if (order.getMode() == 3) {
            return ResultUtil.error("银联退款暂未开放!");
        }
        return ResultUtil.error("错误的订单状态!");
    }

    /**
     * 退款
     *
     * @param orderNo 商户订单号
     * @return
     */
    @PostMapping("/alipay/refund")
    @ResponseBody
    @ApiOperation("支付宝退款")
    public Result refund(@ApiParam("线上订单号") @RequestParam("orderNo") String orderNo) {
        PayOrder order = payService.getOrderByOnlineSn(orderNo);
        if (order == null) {
            return ResultUtil.error("没有发现这个订单！");
        }
        AlipayTradeRefundRequestBuilder builder = new AlipayTradeRefundRequestBuilder()
                .setOutTradeNo(orderNo)
                .setRefundAmount(order.getOfficialReceipts().toString())
                .setRefundReason("订单退款")
                .setOutRequestNo(String.valueOf(System.nanoTime()))
                .setStoreId(String.valueOf(order.getUserId()));
        AlipayF2FRefundResult result = alipayTradeService.tradeRefund(builder);
        switch (result.getTradeStatus()) {
            case SUCCESS:
                if (!payService.changeOrderToRefund(order)) {
                    return ResultUtil.error("订单状态异常!");
                }
                //todo 需要保存退款信息.
                logger.info("支付宝退款成功: )");
                return ResultUtil.success("支付宝退款成功: )");
            case FAILED:
                logger.error("支付宝退款失败!!!");
                return ResultUtil.error("支付宝退款失败!!!");
            case UNKNOWN:
                logger.error("系统异常，订单退款状态未知!!!");
                return ResultUtil.error("系统异常，订单退款状态未知!!!");
            default:
                logger.error("不支持的交易状态，交易返回异常!!!");
                return ResultUtil.error("不支持的交易状态，交易返回异常!!!");
        }

    }


    /**
     * 扫码付异步结果通知,支付宝扫码可以无视
     *
     * @param request
     */
    @RequestMapping("/alipay/notify")
    @ResponseBody
    @ApiOperation("支付宝异步结果通知")
    public Result notify(HttpServletRequest request) throws AlipayApiException {
        // 一定要验签，防止黑客篡改参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((key, value) -> System.out.println(key + "=" + value[0]));

        // https://docs.open.alipay.com/54/106370
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }

        boolean flag = AlipaySignature.rsaCheckV1(params,
                aliPayProperties.getAlipayPublicKey(),
                aliPayProperties.getCharset(),
                aliPayProperties.getSignType());

        if (flag) {
            return ResultUtil.success("成功.");
        }

        return ResultUtil.error("失败.");
    }

    @RequestMapping("/weixin/query")
    @ResponseBody
    @ApiOperation("微信订单查询")
    public Result weixinOrderQuery(String orderNo) {

        Map<String, String> data = new HashMap<>();
        data.put("out_trade_no", orderNo);
        try {
            Map<String, String> result = wxPay.orderQuery(data);
            return ResultUtil.success("成功", result);
        } catch (Exception e) {
            return ResultUtil.error(e.getMessage());
        }
    }


    @GetMapping("/statistics")
    @ResponseBody
    @ApiOperation("统计时间范围内")
    public Result statisticsForTimes(@ApiParam("开始时间") @RequestParam("start") String startTime,
                                     @ApiParam("结束时间") @RequestParam("end") String endTime,
                                     @ApiParam("用户ID") @RequestParam("userId") Integer userId) {
        try {
            //开始时间
            LocalDateTime start = TimeUtil.parseTime(startTime);
            //结束时间
            LocalDateTime end = TimeUtil.parseTime(endTime);
            List<StatisticsTable> list = payService.getStatisticsTable(start, end, userId);
            return ResultUtil.success("成功！", list);
        } catch (RuntimeException e) {
            return ResultUtil.error(e.getMessage());
        }
    }

    //@RequestMapping()
    //public Result

    private AdminUser getUserById(int id) {
        AdminUser user = userMapper.selectById(id);
        Preconditions.checkNotNull(user, "未发现对应的用户");
        if (user.getStatus() != 0) {
            throw new RuntimeException("用户未被启用");
        }
        return user;
    }

    @GetMapping("/selectOrderItem")
    @ApiOperation("查询收银明细")
    @ResponseBody
    public Result selectOrderItemVo(@ApiParam("开始时间") @RequestParam("start") String startTime,
                                    @ApiParam("结束时间") @RequestParam("end") String endTime,
                                    @ApiParam("用户ID") @RequestParam("userId") Integer userId) {
        //开始时间
        LocalDateTime start = TimeUtil.parseTime(startTime);
        //结束时间
        LocalDateTime end = TimeUtil.parseTime(endTime);
        return ResultUtil.success("成功", payOrderItemMapper.selectOrderItemVo(userId, start, end));
    }
}
